#!/usr/bin/python 
# -*- coding: utf-8 -*-

import wx
import time,os
import chardet

from ctrl.notebook import FXNoteBook
from dialog.AboutDialog import AboutDialog
from dialog.ImgDialog import ImgDialog
from util.checkRun import checkRun
from util.ConfigUtil import ConfigUtil

# 菜单栏值
ID_EXIT=200
ID_ABOUT=201
ID_NEW=202
ID_OPEN=203
ID_OPEN_DIR=204
ID_SAVE=205
ID_SAVE_AS=206
ID_UNDO=207
ID_CUT=208
ID_COPY=209
ID_PASTE=210
ID_DELETE=211
ID_SELECT_ALL=212
ID_FIND=213
ID_FIND_NEXT=214
ID_REPLACE=215
ID_CONTROL=2156
ID_REMOTE=217
ID_IMG=218
ID_TIME_DATE=219
ID_CALC=220
ID_GAME=221
ID_JSON=222
ID_CMD=223
ID_HISTORY=224
ID_TOLINE=225
ID_SPLIT=226

'''
框架类
'''
class MainFrame(wx.Frame):
    def __init__(self,parent,id,title,state=0):
        wx.Frame.__init__(self,parent,id,title,size = (800,600)) #size：width、height
        self.SetMinSize((800,600))  # 设置最小尺寸
        self.cwd=os.getcwd()
        self.state=state
        self.app=wx.GetApp()
        #图标
        self.SetIcon(wx.Icon(os.path.abspath(self.cwd+"\\icon\\alienware.png"),type=wx.BITMAP_TYPE_PNG))
        #屏幕中央
        self.Centre()

        #菜单
        self.createMenuBar()

        #工具栏
        self.createTool()

        #查询和替换事件绑定
        self.bindEvent()

        #状态栏
        self.setupStatus()
        #主面板创建
        self.fxnotebook=FXNoteBook(self,-1,state)

        # self.fxnotebook=FXNoteBook(self)

    #------------------------查询和替换事件绑定----------------------------
    def bindEvent(self):
        '''
        查询和替换事件绑定
        '''
        self.finddlg =None
        self.finddata = wx.FindReplaceData()

        self.Bind(wx.EVT_FIND,self.On_Find)
        self.Bind(wx.EVT_FIND_NEXT,self.On_Find)
        self.Bind(wx.EVT_FIND_REPLACE,self.On_Replace)
        self.Bind(wx.EVT_FIND_REPLACE_ALL,self.On_ReplaceAll)
        self.Bind(wx.EVT_FIND_CLOSE,self.On_FindClose)  #销毁查询
        self.Bind(wx.EVT_CLOSE,self.OnQuit) #退出窗口

    #------------------------初始化查找和替换窗口----------------------------
    def _InitFindDialog(self,mode):
        '''
        窗口查找替换功能
        '''
        if self.finddlg:
            self.finddlg.Destroy()
            style=(wx.FR_NOUPDOWN|wx.FR_NOMATCHCASE|wx.FR_NOWHOLEWORD)
        
        if mode == ID_REPLACE:
            style= (wx.FR_NOUPDOWN|wx.FR_NOMATCHCASE|wx.FR_NOWHOLEWORD|wx.FR_REPLACEDIALOG)
            title= '替换'
            dlg = wx.FindReplaceDialog(self,self.finddata,title,style)

        else:
            title='查找'
            dlg=wx.FindReplaceDialog(self,self.finddata,title,style=0)
        self.finddlg=dlg
        self.finddlg.Show()

    #------------------------工具栏----------------------------
    def toolData(self):
        return (
            (ID_NEW,self.cwd+'\\icon\\new.png','新建','新建'),
            (ID_OPEN,self.cwd+'\\icon\\open.png','打开','打开'),
            (ID_SAVE,self.cwd+'\\icon\\save.png','保存','保存'),
            (ID_SAVE_AS,self.cwd+'\\icon\\save_as.png','另存为','另存为'),
            (ID_UNDO,self.cwd+'\\icon\\undo.png','撤销','撤销'),
            (ID_CUT,self.cwd+'\\icon\\cut.png','剪切','剪切'),
            (ID_SELECT_ALL,self.cwd+'\\icon\\select_all.png','全选','全选'),
            (ID_COPY,self.cwd+'\\icon\\copy.png','复制','复制'),
            (ID_PASTE,self.cwd+'\\icon\\paste.png','粘贴','粘贴'),
            (ID_DELETE,self.cwd+'\\icon\\delete.png','删除','删除'),
            (ID_FIND,self.cwd+'\\icon\\search.png','查找','查找'),
            (ID_FIND_NEXT,self.cwd+'\\icon\\search_next.png','查找下一个','查找下一个'),
            (ID_REPLACE,self.cwd+'\\icon\\replace.png','替换','替换'),
            (ID_JSON,self.cwd+'\\icon\\json.png','JSON','json格式化'),
            (ID_TOLINE,self.cwd+'\\icon\\toline.png','行转列','行转列'),
            (ID_TIME_DATE,self.cwd+'\\icon\\time_date.png','时间/日期','时间/日期'),
            (ID_SPLIT,self.cwd+'\\icon\\split.png','拆分窗口','拆分窗口'),
            (ID_IMG,self.cwd+'\\icon\\img.png','图片','图片'),
            (ID_CALC,self.cwd+'\\icon\\calc.png','计算器','计算器'),
            (ID_CONTROL,self.cwd+'\\icon\\control.png','控制面板','控制面板'),
            (ID_REMOTE,self.cwd+'\\icon\\remote.png','远程登录','远程登录'),
            (ID_CMD,self.cwd+'\\icon\\cmd.png','cmd','cmd'),
            # (ID_ABOUT,self.cwd+'\\icon\\about.png','关于','关于')
        )

    def createTool(self):
        '''
        创建工具栏
        '''
        self.toolBar = self.CreateToolBar()
        for eachID,eachJPG,eachPro,eachStatus in self.toolData():
            toolItem =self.toolBar.AddTool(eachID,eachPro,wx.Bitmap(eachJPG),eachStatus)
            self.Bind(wx.EVT_TOOL, self.menuHandler,toolItem)
        self.toolBar.Realize()  #准备显示工具栏

    #------------------------菜单----------------------------
    def menuData(self):
        return (('文件(&F)',('新建(&N)\tCtrl+N',ID_NEW,self.cwd+'\\icon\\new.png'),
            ('打开文件(&O)...\tCtrl+O',ID_OPEN,self.cwd+'\\icon\\open.png'),
            ('保存(&S)\tCtrl+S',ID_SAVE,self.cwd+'\\icon\\save.png'),
            ('另存为(&A)...',ID_SAVE_AS,self.cwd+'\\icon\\save_as.png'),
            ('','',''),
            ('历史记录...',ID_HISTORY,''),
            ('','',''),
            ('退出(&Q)',ID_EXIT,self.cwd+'\\icon\\quit.png')
        ),
        ('编辑(&E)',('撤销(&U)\tCtrl+Z',ID_UNDO,self.cwd+'\\icon\\undo.png'),
            ('','',''),
            ('剪切(&T)\tCtrl+X',ID_CUT,self.cwd+'\\icon\\cut.png'),
            ('复制(&C)\tCtrl+C',ID_COPY,self.cwd+'\\icon\\copy.png'),
            ('粘贴(&P)\tCtrl+V',ID_PASTE,self.cwd+'\\icon\\paste.png'),
            ('删除(&L)\tDel',ID_DELETE,self.cwd+'\\icon\\delete.png'),
            ('','',''),
            ('查找(&F)\tCtrl+F',ID_FIND,self.cwd+'\\icon\\search.png'),
            ('查找下一个(&N)\tF3',ID_FIND_NEXT,self.cwd+'\\icon\\search_next.png'),
            ('替换(&R)\tCtrl+H',ID_REPLACE,self.cwd+'\\icon\\replace.png'),
            ('行转列\tCtrl+G',ID_TOLINE,self.cwd+'\\icon\\toline.png'),
             ('','',''),
            ('全选(&A)\tCtrl+A',ID_SELECT_ALL,self.cwd+'\\icon\\select_all.png'),
            ('时间/日期(&D)\tF5',ID_TIME_DATE,self.cwd+'\\icon\\time_date.png')
        ),
        ('附件(&A)',('计算器',ID_CALC,self.cwd+'\\icon\\calc.png'),
            ('图片',ID_IMG,self.cwd+'\\icon\\img.png'),
            ('控制面板',ID_CONTROL,self.cwd+'\\icon\\control.png'),
            ('远程登录',ID_REMOTE,self.cwd+'\\icon\\remote.png'),
            ('CMD',ID_CMD,self.cwd+'\\icon\\cmd.png')
        ),
        ('视图(&V)',('拆分\tCtrl+P',ID_SPLIT,self.cwd+'\\icon\\split.png')
        ),
        ('帮助(&H)',('关于(&A)',ID_ABOUT,self.cwd+'\\icon\\about.png'))
        )

    def createMenuBar(self):
        '''
        创建菜单 
        '''
        menuBar=wx.MenuBar()  #菜单栏
        for eachMenuData in self.menuData():
            menulLabel = eachMenuData[0]
            menuItems = eachMenuData[1:]
            menuBar.Append(self.createMenu(menuItems),menulLabel)
        
        self.Bind(wx.EVT_MENU, self.menuHandler)  #点击事件
        self.Bind(wx.EVT_MENU_OPEN,self.changeMenu)  #菜单打开事件
        self.SetMenuBar(menuBar)
    
    def changeMenu(self,event):
        '''
        动态生成菜单
        '''
        #删除已有菜单
        for _it in [x for x in self.history.MenuItems]:
            self.history.DestroyItem(_it)
        
        #增加新菜单
        listData = self.fxnotebook.historyList
        if len(listData)>0:
            for one in listData:
                self.history.Append(wx.MenuItem(self.history,int(one),text=listData[one],kind=wx.ITEM_NORMAL))

    def createMenu(self,menuData):
        menu =wx.Menu()  #菜单
        for eachLabel,eachId,eachJPG in menuData:
            if not eachLabel:
                menu.AppendSeparator()
                continue
            
            if ID_HISTORY== eachId:
                self.history=wx.Menu()
                menu.AppendSubMenu(self.history,eachLabel)
            
            else:
                menuItem=wx.MenuItem(menu,eachId,eachLabel)
                menuItem.SetBitmap(wx.Bitmap(eachJPG))
                menu.Append(menuItem)

        return menu

    #------------------------状态栏----------------------------
    def setupStatus(self):
        '''
        创建状态栏
        '''
        #文本
        self.sbar=self.CreateStatusBar(3)  #创建菜案栏
        self.SetStatusWidths([-2,-2,-1])  #比例1:1
        self.SetStatusText("就绪",0)    #第一个对象 第二个再Notify方法中
        self.SetStatusText("",1)
        self.Notify()

        #时间
        self.timer=wx.PyTimer(self.Notify)  #增加时间
        self.timer.Start(1000,wx.TIMER_CONTINUOUS)  #每秒更新

    def Notify(self):
        '''
        定时任务
        '''
        #修改状态栏
        global st
        t=time.localtime(time.time())
        st=time.strftime('%Y-%m-%d %H:%M:%S',t)
        self.SetStatusText(st,2)

        #保存临时文件
        if hasattr(self, 'fxnotebook'):
            self.fxnotebook.saveTmpFile()
    
    #------------------------菜单方法----------------------------
    def menuHandler(self, event):
        '''
        菜单栏点击效果
        '''
        id = event.GetId()
        if id== ID_NEW:  #新建
            self.OnNewFile()
        elif id==ID_OPEN: #打开
            self.OnOpen()
        elif id==ID_SAVE: #保存
            self.OnSave() 
        elif id== ID_SAVE_AS:
            self.OnSaveAs()
        elif id == ID_EXIT: #退出
            exit(0)
        elif id==ID_UNDO: #撤销
            self.OnUndo()
        elif id==ID_CUT: #剪切
            self.OnCut()
        
        elif id == ID_COPY: #复制
            self.OnCopy()
        
        elif id == ID_PASTE: #粘贴
            self.OnPaste()
        elif id == ID_DELETE: #清空
            self.OnClear()

        elif id== ID_SELECT_ALL: #全选
            self.OnSelectAll()

        elif id == ID_FIND:  #查找
            self.OnFind(id)

        elif id ==  ID_FIND_NEXT: #查找下一个
            self.OnFind(id)

        elif id == ID_REPLACE:
            self.OnReplace(id)

        elif id == ID_ABOUT:
            dlg=AboutDialog(None,-1)
            dlg.ShowModal()
            dlg.Destroy()
        
        elif id == ID_TIME_DATE:

            result=self.fxnotebook.getTab()
            x = result.TXResult.GetInsertionPoint()
            result.addDate(x,x,st)
        elif id == ID_JSON:
            self.fxnotebook.jsonFormat()

        elif id == ID_IMG:
            dlg=ImgDialog(None,-1)
            dlg.ShowModal()
            dlg.Destroy()

        elif id == ID_CALC:
            os.startfile("calc.exe")
        elif id== ID_CONTROL:
            os.startfile("control.exe")
        elif id == ID_REMOTE:
            os.startfile("mstsc.exe")
        elif id == ID_CMD:
            os.startfile("cmd.exe")
        elif id == ID_TOLINE:
            self.toLineData()
        elif id==ID_SPLIT:
            self.splitWin()
        else:
            listTmp=self.fxnotebook.historyList
            if id in listTmp:
                self.addTab(listTmp[id])
                self.fxnotebook.removeHistory(id)
                return

            print(id,"No set")
    
    def OnNewFile(self):
        '''
        新建文件
        '''
        self.fxnotebook.addTab("记事本", "","utf-8","",True)
    
    def OnSave(self):
        '''
        保存文件
        '''
        if not self.fxnotebook.getTab():
            return 

        if self.fxnotebook.getTab().TXResult.IsEmpty():
            return 
        
        fileModel=self.fxnotebook.getFile()
        change=0
        if fileModel.path=="":
            filesFilter='Text (*.txt)|*.txt|Python (*.py)|*.py|All files (*.*)|*.*'
            dlg=wx.FileDialog(self,message='保存',defaultDir=self.cwd,defaultFile="",wildcard=filesFilter,style=wx.FD_SAVE)
            if dlg.ShowModal() == wx.ID_OK:
                self.fxnotebook.deleteTmpFile(fileModel.name)

                fileModel.path=dlg.GetPath()
                fileModel.name=os.path.split(dlg.GetPath())[1]
                change=1
            else: 
                return 
        
        cur_content=self.fxnotebook.getTab().TXResult.GetValue()
        fp=open(fileModel.path,'w',encoding=fileModel.encode)
        fp.write(cur_content)
        fp.close()

        if change==1:  #新文件更新标题和记录
            self.fxnotebook.changeTitle(fileModel.name)
            self.fxnotebook.changePageModel(fileModel)
    
    def OnSaveAs(self):
        '''
        另存为
        '''
        if not self.fxnotebook.getTab():
            return 
        
        filesFilter='Text (*.txt)|*.txt|Python (*.py)|*.py|All files (*.*)|*.*'
        dlg=wx.FileDialog(self,message='另存为...',wildcard=filesFilter,style=wx.FD_SAVE)
        if dlg.ShowModal() == wx.ID_OK:
            path=dlg.GetPath()
            if path:
                self.cur_file=path 
                fp=open(path,'w',encoding="utf-8")
                fp.write(self.fxnotebook.getTab().TXResult.GetValue())
                fp.close()
        
        dlg.Destroy()
        self.fxnotebook.getTab().TXResult.Refresh()

    def OnOpen(self):
        '''
        打开文件
        '''
        filesFilter='Text (*.txt)|*.txt|Python (*.py)|*.py|All files (*.*)|*.*'
        dlg=wx.FileDialog(self,'打开文件',self.cwd,"",wildcard=filesFilter,style=wx.FD_OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            self.addTab(dlg.GetPath())

        dlg.Destroy()
    
    def addTab(self,filePath):
        '''
        添加分栏
        '''
        if not os.path.exists(filePath):
            wx.MessageBox('文件: '+filePath+' 不存在', '异常',wx.OK|wx.ICON_WARNING)
            return

        filename=os.path.basename(filePath)
        try:
            with open(filePath, 'rb') as f:
                data = f.read(1024)
                encode=chardet.detect(data)['encoding'].lower()

            if encode =='gb2312':
                encode='gbk'

            with open(filePath,'r',encoding=encode) as f:
                self.fxnotebook.addTab(filename,filePath,encode,f.read(),False)

            self.SetStatusText('文件名: '+filename+" 编码: "+encode,0) 
            self.fxnotebook.getTab().changeStatus()
        except BaseException as exception:
            print(exception)
            wx.MessageBox('文件:'+filename+' 读取异常', '文件解析异常',wx.OK|wx.ICON_WARNING)

    def OnUndo(self):
        '''
        撤销
        '''
        if not self.fxnotebook.getTab():
            return 
        self.fxnotebook.getTab().TXResult.Undo()
    
    def OnCut(self):
        '''
        剪切
        '''
        if not self.fxnotebook.getTab():
            return 
        self.fxnotebook.getTab().TXResult.Cut()
    
    def OnCopy(self):
        '''
        复制
        '''
        if not self.fxnotebook.getTab():
            return 
        self.text_obj=wx.TextDataObject() #获得文本框对象
        self.text_obj.SetText(self.fxnotebook.getTab().TXResult.GetStringSelection())
        if wx.TheClipboard.IsOpened() or wx.TheClipboard.Open():
            wx.TheClipboard.SetData(self.text_obj)
            wx.TheClipboard.Close()
        
        else:
            wx.MessageBox('打开剪切板异常','异常')
    
    def toLineData(self):
        '''
        数据列转行
        '''
        if not self.fxnotebook.getTab():
            return 
        self.fxnotebook.getTab().toLine()

    def OnPaste(self):
        '''
        粘贴
        '''
        if not self.fxnotebook.getTab():
            return 
        text_obj=wx.TextDataObject()
        if wx.TheClipboard.IsOpened() or wx.TheClipboard.Open():
            if wx.TheClipboard.GetData(text_obj):
                result=self.fxnotebook.getTab()
                x = result.TXResult.GetInsertionPoint()
                result.addDate(x,x,text_obj.GetText())
            
            wx.TheClipboard.Close()
        else:
            print("粘贴板未打开")
    
    def OnClear(self):
        '''
        清空
        '''
        if not self.fxnotebook.getTab():
            return 
        
        csel = self.fxnotebook.getTab().TXResult.GetSelection()
        if len(csel.GetRanges())>0:
            start,end=csel.GetRanges()[-1].Get()

            self.fxnotebook.getTab().TXResult.Remove(start,end+1)
            self.fxnotebook.getTab().TXResult.Refresh()

    def OnSelectAll(self):
        '''
        全选
        '''
        if not self.fxnotebook.getTab():
            return 
        self.fxnotebook.getTab().TXResult.SelectAll()
    
    def OnFind(self,id):
        '''
        查找
        '''
        if id in (ID_FIND,ID_FIND_NEXT):
            self._InitFindDialog(id)
        else:
            print("未发现该类型: ",id)
    
    def On_Find(self,event):
        '''
        查找
        '''
        findstr=self.finddata.GetFindString()
        if not self.FindString(findstr):
            # wx.Bell()
            message=('未找到查询内容或已到底部')
            style = wx.YES_NO|wx.ICON_WARNING|wx.CENTER
            result =wx.MessageBox(message,'查找结果提示？',style=style)
            if result == wx.YES:
                self.fxnotebook.getTab().TXResult.SetInsertionPoint(0)
            else:
                self.On_FindClose(None)
    
    def On_Replace(self,event):
        '''
        替换
        '''
        if not self.fxnotebook.getTab():
            return 
        
        rstring =self.finddata.GetReplaceString()
        fstring = self.finddata.GetFindString()
        self.fxnotebook.getTab().TXResult.SetInsertionPoint(0)
        cpos = self.fxnotebook.getTab().TXResult.GetInsertionPoint()
        start,end = cpos,cpos
        if fstring:
            if self.FindString(fstring):
                csel = self.fxnotebook.getTab().TXResult.GetSelection()
                if len(csel.GetRanges())>0:
                    start,end=csel.GetRanges()[-1].Get()
                    self.fxnotebook.getTab().addDate(start,end+1,rstring)

    def On_ReplaceAll(self,event):
        '''
        替换全部
        '''
        if not self.fxnotebook.getTab():
            return 
        rstring =self.finddata.GetReplaceString()
        fstring = self.finddata.GetFindString()
        text = self.fxnotebook.getTab().TXResult.GetValue()
        newtext=text.replace(fstring,rstring)
        self.fxnotebook.getTab().addDate(0,len(text),newtext)
    
    def On_FindClose(self,event):
        '''
        关闭
        '''
        if self.finddlg:
            self.finddlg.Destroy()
            self.finddlg=None

    def FindString(self,findstr):
        '''
        字符串查找
        '''
        if not self.fxnotebook.getTab():
            return 
            
        text = self.fxnotebook.getTab().TXResult.GetValue()
        csel = self.fxnotebook.getTab().TXResult.GetSelection()

        if len(csel.GetRanges())==0:
            cpos = self.fxnotebook.getTab().TXResult.GetInsertionPoint()
        else:
            start,end=csel.GetRanges()[-1].Get()
            if start==end:
                end+=1
            cpos=end

        text= text.upper()  #变小写
        findstr = findstr.upper() #变小写
        found = text.find(findstr,cpos,len(text))
        if found != -1:
            end = found + len(findstr)
            self.fxnotebook.getTab().TXResult.SetSelection(found,end)
            self.fxnotebook.getTab().TXResult.SetFocus()
            return True
        return False

    def OnFindNext(self,id):
        '''
        查找下一个
        '''
        if id in wx.ID_FIND:
            self._InitFindDialog(id)
        else:
            print("查找下一个未发现该类型: ",id)
    
    def OnReplace(self,id):
        '''
        替换
        '''
        if id in (ID_REPLACE,):
            self._InitFindDialog(id)
        else:
            print("替换未发现该类型: ",id)

    def splitWin(self):
        '''
        拆分窗口
        '''
        if len(self.fxnotebook.panels)>1:
            fileModel,context=self.fxnotebook.splitWin()
            if fileModel:
                frame=MainFrame(None,-1,'wxedit-children',1)
                frame.fxnotebook.addTab(fileModel.name, fileModel.path,fileModel.encode,context,True)
                frame.Show(True)

                self.app.frameList.append(frame)
        else:
             wx.MessageBox("文件数小于2", '提醒',wx.OK|wx.ICON_WARNING)  

    def childQuit(self):
        self.timer.Stop()
        self.fxnotebook.state=1  #修改状态保存所有文件和内容
        self.fxnotebook.saveTmpFile() # 存储临时文件
        self.fxnotebook.addTmpFile()  #移动文件到主窗口
        self.Destroy()

    def OnQuit(self,event):
        '''
        关闭应用
        '''
        #关闭为主窗口，先关闭子窗口
        if self.state==0 and len(self.app.frameList)>0: #主窗口
            dlg = wx.MessageDialog(self,"关闭主窗口将关闭所有窗口，是否继续？","提醒",wx.YES_NO|wx.ICON_QUESTION)
            retCode=dlg.ShowModal()

            if retCode==wx.ID_NO: #否
                return

            #关闭所有子窗口
            for one in self.app.frameList:
                one.childQuit()
        
        else:  #子窗口
            #删除自身记录
            if len(self.app.frameList)>0:
                for i,one in enumerate(self.app.frameList):
                    if one == self:
                        del self.app.frameList[i]

        self.childQuit()
        event.Skip()
    
    def changeFontSize(self,value=0):
        '''
        加大字体
        '''
        if value==0:
            self.app.fontSize+=1
        else:
            if self.app.fontSize>5: #最小为5
                self.app.fontSize-=1
            else:
                return
        
        self.app.config.changeSize(self.app.fontSize)
        if len(self.app.frameList)>0:
            for i,one in enumerate(self.app.frameList):
                one.fxnotebook.changeFontSize(self.app.fontSize)

        if self.state==0: #主窗口
            self.fxnotebook.changeFontSize(self.app.fontSize)
        else: #子窗口
            self.app.frame.fxnotebook.changeFontSize(self.app.fontSize)


class App(wx.App):
    '''
    app类
    '''
    def __init__(self):
        # 重写__init__必须调用wx.APP的__init__，否则OnInit方法不会被调用
        super(self.__class__,self).__init__()
        self.num=0 #子窗口数
        self.config=ConfigUtil()
        fontSize,backgroudColor=self.config.read()
        self.fontSize=fontSize
        
        self.frame=MainFrame(None,-1,'wxedit')
        self.frame.Show(True)
        self.frameList=[]

if __name__ == "__main__":
    checkRun=checkRun()
    if not checkRun.checkState():
        checkRun.writeId()
        app=App()
        app.MainLoop()